/*
 * author      : 吴中勤 
 * date        : 2019/1/23
 * description : TODO
 */

import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.util.ElementScanner8;
import javax.tools.Diagnostic;

public class NameChecker {
    private final Messager messager;

    NameCheckScanner nameCheckScanner = new NameCheckScanner();

    NameChecker(ProcessingEnvironment processingEvn) {
        this.messager = processingEvn.getMessager();
    }

    void checkName(Element element) {
        nameCheckScanner.scan(element);
    }

    // 检查类名／方法名
    private class NameCheckScanner extends ElementScanner8<Void, Void> {

        /**
         * 检查java类
         */
        @Override
        public Void visitType(TypeElement e, Void p) {
            scan(e.getTypeParameters(), p);
            checkCamelCase(e, true);
            super.visitType(e, p);
            return null;
        }

        /**
         * 检查方法命名
         */
        @Override
        public Void visitExecutable(ExecutableElement e, Void p) {
            if (e.getKind() == ElementKind.METHOD) {
                Name name = e.getSimpleName();
                if (name.contentEquals(e.getEnclosingElement().getSimpleName())) {
                    messager.printMessage(Diagnostic.Kind.WARNING, "方法名与类名重复");
                }
                checkCamelCase(e, false);
            }
            super.visitExecutable(e, p);
            return null;
        }

//        private boolean heuristicallyConstant(VariableElement e) {
//            if (e.getEnclosingElement().getKind() == ElementKind.INTERFACE) return true;
//            if (e.getKind() == ElementKind.FIELD
//                    && e.getModifiers().containsAll(EnumSet.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL))) {
//                return true;
//            }
//            return false;
//        }

        private void checkCamelCase(Element e, boolean initialCaps) {
            String name = e.getSimpleName().toString();
            boolean previousUpper = false;
            boolean conventional = true;
            int firstCodePoint = name.codePointAt(0);

            if (Character.isUpperCase(firstCodePoint)) {
                previousUpper = true;
                if (!initialCaps) {
                    messager.printMessage(Diagnostic.Kind.WARNING, "名称\"" + name + "\"应当小写字母开头", e);
                    return;
                }
            } else if (Character.isLowerCase(firstCodePoint)) {
                previousUpper = false;
                if (initialCaps) {
                    messager.printMessage(Diagnostic.Kind.WARNING, "名称\"" + name + "\"应当大写字母开头", e);
                    return;
                }
            } else {
                conventional = false;

            }

            if (conventional) {
                int cp = firstCodePoint;
                for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {
                    cp = name.codePointAt(i);
                    if (Character.isUpperCase(cp)) {
                        if (previousUpper) {
                            conventional = false;
                            break;
                        }
                        previousUpper = true;
                    } else {
                        previousUpper = false;
                    }
                }
            }

            if (!conventional) {
                messager.printMessage(Diagnostic.Kind.WARNING, "名称\"" + name + "\"应当符合驼峰驼背命名法", e);
            }
        }
    }
}
